函數式範型將開發者的思維模式從「更新一個有狀態的盒子」轉變為 應用數學上的轉換 到不可變值。在 Elixir 中,資料永遠不會被改變;它只會以全新的形式重生。
1. 數學上的陳述
當你寫下 $x = a + 1$ 時,並不是將結果賦予變數。相反地,你只是簡單地 陳述 表示表達式 $x$ 與 $a + 1$ 具有相同的值。這類似於代數邏輯,在特定情境中 $x$ 代表一個固定的值。
2. 不可變性作為保障
在 Elixir 中, 所有值都是不可變的。資料一旦建立便無法更改。這消除了「副作用」——即某個函數可能意外修改全域變數或傳入的物件——確保程式碼具有可預測性且執行緒安全。
3. 轉換與變更之別
我們從不就地修改資料。Elixir 沒有賦值運算子;相反地,它試圖 將值與模式進行匹配。要「改變」一個值,我們會將原始資料傳遞給一個函數,產生一個完全新的版本。
iex> name = "elixir"
"elixir"
iex> cap_name = String.capitalize name
"Elixir"
iex> name
"elixir"(依然完好無損!)
"elixir"
iex> cap_name = String.capitalize name
"Elixir"
iex> name
"elixir"(依然完好無損!)
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
In Elixir, what does the expression
x = a + 1 represent?A command to allocate a new memory box for x.
An assertion that x and a + 1 have the same value.
A mutable assignment operator.
A way to delete the previous value of a.
✅ Correct!
Correct! In functional programming, the equals sign is a match/assertion, not an assignment.❌ Incorrect
Elixir uses matching. You are declaring that both sides are equal, not commanding a state change.QUESTION 2
What is the result of
name after executing cap_name = String.capitalize(name)?The value of 'name' is updated to start with a capital letter.
The 'name' variable is deleted from memory.
The value of 'name' remains exactly as it was originally created.
An error occurs because you cannot re-use 'name'.
✅ Correct!
Because data is immutable, String.capitalize creates a *new* string; the original 'name' is untouched.❌ Incorrect
Recall the rule: data cannot be altered once created. Any transformation results in a new value.QUESTION 3
Which of these statements is a core Logic Rule of Elixir?
Data should be modified in place for performance.
All values are immutable.
Variables are global by default.
Strings can be appended to directly.
✅ Correct!
Immutability is the foundational guarantee of Elixir and the BEAM VM.❌ Incorrect
In functional languages, we never modify data in place; we only transform it.QUESTION 4
Why is immutability beneficial for concurrent programming?
It requires more RAM, which makes systems faster.
It allows multiple threads to change data simultaneously.
It eliminates race conditions because data cannot be changed under your feet.
It automatically recompiles the code.
✅ Correct!
If data cannot change, you don't need complex locks or mutexes to prevent corruption.❌ Incorrect
Think about 'side effects'. If data is immutable, no other part of the system can change what you are looking at.QUESTION 5
What happens in Snippet 2:
array = [1,2,3]; do_something_with(array); print(array)?The output is guaranteed to be [1,2,3].
The output depends on what do_something_with does.
The output will be empty if the function sorted the list.
The array is cleared from memory.
✅ Correct!
Predictability is the default. Since Elixir lacks in-place modification, the array remains [1,2,3].❌ Incorrect
Even if the function 'modifies' the array, it only returns a NEW version. The original binding is safe.Case Study: The Predictable System
Immutability in Practice
You are debugging a legacy system where a list of user IDs is passed through five different processing functions. In an imperative language, you are worried one function might be clearing the list. In Elixir, you see the following code:
count = 99
process_data(count)
IO.puts count
Q
Explain why the output of IO.puts count is guaranteed to be 99 regardless of what process_data does.
Solution:
Because all values in Elixir are immutable. The variable 'count' points to the integer 99. When passed to 'process_data', the function receives a copy of the value (or a reference to the immutable data). Since Elixir does not have assignment and cannot modify memory in place, 'process_data' cannot overwrite the memory location of 'count'.
Because all values in Elixir are immutable. The variable 'count' points to the integer 99. When passed to 'process_data', the function receives a copy of the value (or a reference to the immutable data). Since Elixir does not have assignment and cannot modify memory in place, 'process_data' cannot overwrite the memory location of 'count'.
Q
If process_data needs to increment the count, how would it return that value to the caller?
Solution:
The function must return the NEW transformed value. The caller would then need to bind that result to a new variable name (e.g., `new_count = process_data(count)`) or rebind the existing label if appropriate within that scope.
The function must return the NEW transformed value. The caller would then need to bind that result to a new variable name (e.g., `new_count = process_data(count)`) or rebind the existing label if appropriate within that scope.